home *** CD-ROM | disk | FTP | other *** search
- UNIT Patrol;
- {-------------------------------------------}
- (*
- ©1988 by Steve Seaquist. All rights reserved.
- Used by permission. Use at your own risk.
- No warranty is expressed or implied.
-
- This Macintosh virus-detecting program was
- originally published and explained in the
- February 1989 issue of MacTutor magazine.
- Some aspects of its design are important to
- security, and it uses some unusual
- techniques, so please read the article.
- *)
- {-------------------------------------------}
- INTERFACE
- USES
- MacIntf,BitProcs,Globals;
-
- PROCEDURE BuildDirname;
- PROCEDURE InitPatrols;
- PROCEDURE PatrolDirectories
- (pOnly1Deep:BOOLEAN);
- PROCEDURE PatrolEverything;
- PROCEDURE PatrolFiles;
-
- {*******************************************}
- IMPLEMENTATION
- {$R-}
-
- CONST
- kPatsInitd = -12345;
-
- TYPE
- TOverlappingPBs =
- RECORD
- CASE INTEGER OF
- 0: (fPBRec: HParamBlockRec);
- 1: (fCPBRec: CInfoPBRec);
- END;
-
- VAR
- gAAPatImpl: SignedByte;
- gAppDirId: LONGINT;
- gAppVRefNum: INTEGER;
- gInitdFlag: LONGINT;
- gOnly1Deep: BOOLEAN;
- gOrigWDRefNum: INTEGER;
- gPBs: TOverlappingPBs;
- gSFLst: SFTypeList;
- gSysDirId: LONGINT;
- gSysVRefNum: INTEGER;
- gWDPBRec: WDPBRec;
- gZZPatImpl: SignedByte;
-
- {-------------------------------------------}
- PROCEDURE BuildDirname;
- VAR
- sErr: OSErr;
- sLen: INTEGER;
- sName: Str255;
- sPBs: TOverlappingPBs;
- BEGIN
- IF gOption[eTrace] THEN
- Trace('BuildDirname');
- WITH sPBs,fPBRec,fCPBRec DO
- BEGIN
- sPBs := gPBs;
- ioNamePtr := @sName;
- ioVRefNum := gCurrWDRefNum;
- gCurrDirname := '';
- IF gHFS THEN
- BEGIN
- ioFDirIndex := -1;
- ioDrParID := 0;
- REPEAT
- ioDrDirId := ioDrParID;
- sErr := PBGetCatInfo(@fCPBRec,FALSE);
- IF (sErr <> NoErr) THEN
- EXIT(BuildDirname);
- sLen :=
- LENGTH(sName)+1+LENGTH(gCurrDirname);
- IF (sLen <= 255) THEN
- gCurrDirname :=
- CONCAT(sName,':',gCurrDirname);
- UNTIL ioDrDirId = 2;
- END
- ELSE
- BEGIN
- sErr := PBGetVol(@fPBRec,FALSE);
- IF (sErr = NoErr) THEN
- gCurrDirname := CONCAT(sName,':');
- END;
- END;
- END;
- {-------------------------------------------}
- PROCEDURE CallProcessFile;
- BEGIN
- gActiveSelf :=
- (gCurrVRefNum = gAppVRefNum) AND
- (gCurrDirId = gAppDirId) AND
- (gCurrFilename = StringPtr(kCurApName)^);
- gActiveSys :=
- (gCurrVRefNum = gSysVRefNum) AND
- (gCurrDirId = gSysDirId) AND
- (gCurrFilename = StringPtr(kSysResName)^);
- gCurrFileDeleted := FALSE;
- ProcessFile;
- END;
- {-------------------------------------------}
- PROCEDURE FloatWDDeeper
- (pDrDirId: LONGINT);
- BEGIN
- IF gOption[eTrace] THEN
- TraceNbr('Begin FloatWDDeeper, WD = ',
- ORD4(gCurrWDRefNum));
- WITH gPBs,fCPBRec DO
- BEGIN
- IF NOT((pDrDirId=0) OR (pDrDirId=2)) THEN
- BEGIN
- gWDPBRec.ioVRefNum := gCurrWDRefNum;
- gWDPBRec.ioWDDirId := 0;
- gError := PBCloseWD(@gWDPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t close WD');
- EXIT(FloatWDDeeper);
- END;
- END;
- gWDPBRec.ioVRefNum := gCurrVRefNum;
- gWDPBRec.ioWDDirId := ioDrDirId;
- gError := PBOpenWD(@gWDPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t open subdir WD');
- EXIT(FloatWDDeeper);
- END;
- gCurrWDRefNum := gWDPBRec.ioVRefNum;
- END;
- IF gOption[eTrace] THEN
- TraceNbr('End FloatWDDeeper, WD = ',
- ORD4(gCurrWDRefNum));
- END;
- {-------------------------------------------}
- PROCEDURE FloatWDShallower
- (pDrDirId: LONGINT);
- BEGIN
- IF gOption[eTrace] THEN
- TraceNbr('Begin FloatWDShallower, WD = ',
- ORD4(gCurrWDRefNum));
- WITH gPBs,fCPBRec DO
- BEGIN
- gError := PBCloseWD(@gWDPBRec,FALSE);
- gWDPBRec.ioVRefNum := gCurrWDRefNum;
- gWDPBRec.ioWDDirId := 0;
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t close subdir WD');
- EXIT(FloatWDShallower);
- END;
- IF (pDrDirId = 0)
- OR (pDrDirId = 2) THEN
- gCurrWDRefNum := gOrigWDRefNum
- ELSE
- BEGIN
- gWDPBRec.ioVRefNum := gCurrVRefNum;
- gWDPBRec.ioWDDirId := pDrDirId;
- gError := PBOpenWD(@gWDPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t reopen WD');
- EXIT(FloatWDShallower);
- END;
- gCurrWDRefNum := gWDPBRec.ioVRefNum;
- END;
- END;
- IF gOption[eTrace] THEN
- TraceNbr('End FloatWDShallower, WD = ',
- ORD4(gCurrWDRefNum));
- END;
- {-------------------------------------------}
- PROCEDURE GetActualDirId
- (pDrDirId: LONGINT);
- BEGIN
- WITH gPBs,fCPBRec DO
- BEGIN
- ioDrDirId := pDrDirId;
- ioFDirIndex := -1;
- ioVRefNum := gOrigWDRefNum;
- gError := PBGetCatInfo(@fCPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t GetActualDirId');
- EXIT(GetActualDirId);
- END;
- gCurrDInfo := ioDrUsrWds;
- gCurrDirId := ioDrDirId;
- IF gOption[eTrace] THEN
- TraceNbr('ActualDirID = ',gCurrDirId);
- END;
- END;
- {-------------------------------------------}
- PROCEDURE InitPatrols;
- BEGIN
- IF gOption[eTrace] THEN
- Trace('InitPatrols');
- WITH gPBs,fPBRec,fCPBRec DO
- BEGIN
- ZeroOutRange(@gAAPatImpl,@gZZPatImpl);
- gHFS := TWordPtr(kSFCBLen)^ > 0;
-
- ioNamePtr := @gCurrFilename;
- IF gHFS THEN
- BEGIN
- gError := GetVRefNum
- (TWordPtr(kSysMap)^,gSysVRefNum);
- IF (gError <> NoErr) THEN
- ErrorOSErr('Couldn’t get act sys vol');
- ioVRefNum := gSysVRefNum;
- gError := PBHGetVInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- ErrorOSErr('Couldn’t get act sys dir');
- IF (fPBRec.ioVFndrInfo[1] = 0) THEN
- ErrorOSErr('Boot vol not Blessed');
- gSysDirId := ioVFndrInfo[1];
- gError := PBHGetVol(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- ErrorOSErr('Couldn’t get own DirId');
- gAppDirId := ioDirId;
- gCurrDirId := ioDirId;
- gCurrWDRefNum := ioVRefNum;
- ioVolIndex := 0;
- gError := PBHGetVInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- ErrorOSErr('Couldn’t get own VInfo');
- gAppVRefNum := ioVRefNum;
- END
- ELSE
- BEGIN
- gSysVRefNum := TWordPtr(kBootDrive)^;
- gError := PBGetVol(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- ErrorOSErr('Couldn’t get own Vol');
- gAppVRefNum := ioVRefNum;
- gCurrWDRefNum := ioVRefNum;
- gAppDirId := 2;
- gSysDirId := 2;
- gCurrDirId := 2;
- END;
- BuildDirname;
- gCurrFilename := StringPtr(kCurApName)^;
- ioFDirIndex := 0;
- ioDirId := 0;
- ioVRefNum := gCurrWDRefNum;
- gError := PBGetFInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- ErrorOSErr('Couldn’t get own FInfo');
- gCurrFInfo := ioFlFndrInfo;
- gActiveSelf := TRUE;
- gActiveSys := FALSE;
-
- gWDPBRec.ioWDProcID := $50617472; {'Patr'}
- gInitdFlag := kPatsInitd;
- END;
- END;
- {-------------------------------------------}
- PROCEDURE PatrolDir
- (pDrDirId: LONGINT);
- VAR
- sIndex: INTEGER;
- BEGIN
- IF gOption[eTrace] THEN
- TraceNbr('PatrolDir ',pDrDirId);
- WITH gPBs,fCPBRec DO
- BEGIN
- IF (gInitdFlag <> kPatsInitd) THEN
- BEGIN { shouldn't happen }
- ErrorOSErr('InitPatrols not done');
- EXIT(PatrolDir);
- END;
- IF gHFS THEN
- BEGIN
- gCurrDirId := pDrDirId;
- GetActualDirId(pDrDirId);
- IF (gError <> NoErr) THEN
- EXIT(PatrolDir);
- END
- ELSE
- gCurrDirId := 2;
- BuildDirname;
- DirectoryBegins;
-
- sIndex := 1;
- REPEAT
- gCurrIndex := sIndex;
- ioFDirIndex := sIndex;
- ioDrDirId := 0;
- ioVRefNum := gCurrWDRefNum;
- gError := PBGetFInfo(@fPBRec,FALSE);
- IF (gError = NoErr) THEN
- BEGIN
- gCurrFInfo := ioFlFndrInfo;
- CallProcessFile;
- END
- ELSE IF (gError <> fnfErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get a file');
- EXIT(PatrolDir);
- END;
- IF NOT(gCurrFileDeleted) THEN
- INC(sIndex);
- UNTIL (gError <> NoErr) OR gAbortPatrol;
- IF gAbortPatrol THEN
- EXIT(PatrolDir);
- IF (gError <> fnfErr) THEN
- BEGIN
- ErrorOSErr('Error at end of files');
- EXIT(PatrolDir);
- END;
- gError := NoErr;
-
- IF gHFS AND NOT(gOnly1Deep) THEN
- BEGIN
- sIndex := 1;
- REPEAT
- gCurrIndex := sIndex;
- ioFDirIndex := sIndex;
- ioDrDirId := 0;
- ioVRefNum := gCurrWDRefNum;
- gError := PBGetCatInfo(@fCPBRec,FALSE);
- IF (gError = NoErr) THEN
- BEGIN
- IF BTst(ORD4(ioFlAttrib),4) THEN
- BEGIN
- FloatWDDeeper (pDrDirId);
- IF (gError <> NoErr) THEN
- EXIT(PatrolDir);
-
- PatrolDir(ioDrDirId);
- IF (gError <> NoErr)
- AND (pDrDirId <> 0)
- AND (pDrDirId <> 2) THEN
- EXIT(PatrolDir);
-
- FloatWDShallower(pDrDirId);
- IF (gError <> NoErr) THEN
- EXIT(PatrolDir);
- END;
- END
- ELSE IF (gError <> fnfErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get a dir');
- EXIT(PatrolDir);
- END;
- INC(sIndex);
- UNTIL (gError <> NoErr) OR gAbortPatrol;
- IF gAbortPatrol THEN
- EXIT(PatrolDir);
- IF (gError <> fnfErr) THEN
- BEGIN
- ErrorOSErr('Error at end of subdirs');
- EXIT(PatrolDir);
- END;
- gError := NoErr;
- gCurrDirId := pDrDirId;
- GetActualDirId(pDrDirId);
- IF (gError <> NoErr) THEN
- EXIT(PatrolDir);
- BuildDirname;
- END;
-
- DirectoryEnds;
- END;
- END;
- {-------------------------------------------}
- PROCEDURE PatrolDirectories
- (pOnly1Deep:BOOLEAN);
- BEGIN
- IF gOption[eTrace] THEN
- Trace('PatrolDirectories ');
- WITH gPBs,fPBRec,fCPBRec,gSFRep DO
- BEGIN
- IF (gInitdFlag <> kPatsInitd) THEN
- BEGIN { shouldn't happen }
- ErrorOSErr('InitPatrols not done');
- EXIT(PatrolDirectories);
- END;
- gOnly1Deep := pOnly1Deep;
-
- SFGetFile
- (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
- WHILE good DO
- BEGIN
- IF gHFS THEN
- BEGIN
- ioVRefNum := gSFRep.vRefNum;
- ioVolIndex := 0;
- gError := PBHGetVInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get own VInfo');
- LEAVE;
- END;
- gCurrVRefNum := ioVRefNum;
- END
- ELSE
- gCurrVRefNum := vRefNum;
- gCurrWDRefNum := vRefNum;
- gOrigWDRefNum := vRefNum;
- PatrolBegins;
- PatrolDir(0);
- PatrolEnds;
- IF (gError <> NoErr) THEN
- LEAVE;
- SFGetFile
- (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
- END;
-
- gError := NoErr;
- END;
- END;
- {-------------------------------------------}
- PROCEDURE PatrolEverything;
- VAR
- sIndex: INTEGER;
- BEGIN
- IF gOption[eTrace] THEN
- Trace('PatrolEverything ');
- WITH gPBs,fPBRec,fCPBRec DO
- BEGIN
- IF (gInitdFlag <> kPatsInitd) THEN
- BEGIN { shouldn't happen }
- ErrorOSErr('InitPatrols not done');
- EXIT(PatrolEverything);
- END;
- gOnly1Deep := FALSE;
- PatrolBegins;
-
- ioVRefNum := 0;
- sIndex := 1;
- REPEAT
- gCurrIndex := sIndex;
- ioVolIndex := sIndex;
- gError := PBGetVInfo(@fPBRec,FALSE);
- IF (gError = NoErr) THEN
- BEGIN
- gCurrVRefNum := ioVRefNum;
- gCurrWDRefNum := ioVRefNum;
- gOrigWDRefNum := ioVRefNum;
-
- PatrolDir(2);
-
- IF (gError <> NoErr) THEN
- EXIT(PatrolEverything);
- INC(sIndex);
- END
- ELSE IF (gError <> nsvErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get a volume');
- EXIT(PatrolEverything);
- END;
- UNTIL gError <> NoErr;
- IF (gError <> nsvErr) THEN
- BEGIN
- ErrorOSErr('Error at end of volumes');
- EXIT(PatrolEverything);
- END;
-
- gError := NoErr;
- PatrolEnds;
- END;
- END;
- {-------------------------------------------}
- PROCEDURE PatrolFiles;
- VAR
- sPrevDirId: LONGINT;
- sPrevVRefNum: INTEGER;
- sPrevWDRefNum:INTEGER;
- {------------------------}
- PROCEDURE CallPrevDirEnd;
- VAR
- sTempDirId: LONGINT;
- sTempVRefNum: INTEGER;
- sTempWDRefNum:INTEGER;
- BEGIN
- IF (sPrevWDRefNum <> 0) THEN
- BEGIN
- sTempDirId := gCurrDirId;
- sTempVRefNum := gCurrVRefNum;
- sTempWDRefNum := gCurrWDRefNum;
- gCurrDirId := sPrevDirId;
- gCurrVRefNum := sPrevVRefNum;
- gCurrWDRefNum := sPrevWDRefNum;
- DirectoryEnds;
- gCurrDirId := sTempDirId;
- gCurrVRefNum := sTempVRefNum;
- gCurrWDRefNum := sTempWDRefNum;
- END;
- END;
- {------------------------}
- BEGIN
- IF gOption[eTrace] THEN
- Trace('PatrolFiles ');
- WITH gPBs,fPBRec,fCPBRec,gSFRep DO
- BEGIN
- IF (gInitdFlag <> kPatsInitd) THEN
- BEGIN { shouldn't happen }
- ErrorOSErr('InitPatrols not done');
- EXIT(PatrolFiles);
- END;
- PatrolBegins;
-
- sPrevWDRefNum := 0;
- SFGetFile
- (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
- WHILE good DO
- BEGIN
- IF gHFS THEN
- BEGIN
- ioVRefNum := gSFRep.vRefNum;
- ioDrDirId := 0;
- ioFDirIndex := -1;
- gError := PBGetCatInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get DirId');
- LEAVE;
- END;
- gCurrDirId := ioDrDirId;
- ioVolIndex := 0;
- gError := PBHGetVInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get VInfo');
- LEAVE;
- END;
- gCurrVRefNum := ioVRefNum;
- END
- ELSE
- BEGIN
- gCurrDirId := 2;
- gCurrVRefNum := vRefNum;
- END;
- gCurrFilename := fName;
- gCurrIndex := 0;
- gCurrWDRefNum := vRefNum;
- IF (sPrevWDRefNum <> gCurrWDRefNum) THEN
- BEGIN
- CallPrevDirEnd;
- BuildDirname;
- DirectoryBegins;
- sPrevDirId := gCurrDirId;
- sPrevVRefNum := gCurrVRefNum;
- sPrevWDRefNum := gCurrWDRefNum;
- END;
- ioDrDirId := gCurrDirId;
- ioFDirIndex := gCurrIndex;
- ioVRefNum := gCurrWDRefNum;
- gError := PBGetFInfo(@fPBRec,FALSE);
- IF (gError <> NoErr) THEN
- BEGIN
- ErrorOSErr('Couldn’t get FInfo');
- LEAVE;
- END;
- gCurrFInfo := ioFlFndrInfo;
- CallProcessFile;
- IF gAbortPatrol THEN
- LEAVE;
- SFGetFile
- (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
- END;
-
- gError := NoErr;
- CallPrevDirEnd;
- PatrolEnds;
- END;
- END;
- {*******************************************}
- END.